#include "lua_share.h"
#include "Win32Utils/CFileMappingHelper.h"
#include <map>

std::map<_tstring, CFileMappingHelper*> g_share;

static luaL_Reg lib_functions[] =
{
    { "create", &lua_share::create},
    { "read", &lua_share::read},
    { "write", &lua_share::write},
    { NULL, NULL}
};

void lua_share::initialize(lua_State* L, const char* lib_name)
{
    lua_newtable(L);

    luaL_Reg* fun_info = lib_functions;
    while (fun_info->func)
    {
        lua_pushcfunction(L, fun_info->func);
        lua_setfield(L, -2, fun_info->name);
        fun_info++;
    }
    lua_setfield(L, -2, lib_name);
}

void lua_share::uninitialize()
{
    for (auto& item : g_share)
    {
        delete item.second;
    }

    g_share.clear();
}

int lua_share::create(lua_State* L)
{
    std::string name;
    int size = 4096;
    int nTop = lua_gettop(L);

    if (nTop >= 1 && lua_isstring(L, 1))
    {
        name = lua_tostring(L, 1);
    }

    if (nTop >= 2 && lua_isnumber(L, 2))
    {
        size = lua_tointeger(L, 2);
    }

    bool fResult = false;
    if (g_share.end() == g_share.find(name))
    {
        std::string mutex_name = name + "_mutex";
        CFileMappingHelper* obj = new CFileMappingHelper();
        if (obj->Initialize(name.c_str(), mutex_name.c_str(), size))
        {
            g_share.insert(std::make_pair(name, obj));
            fResult = true;
        }
    }

    lua_pushboolean(L, fResult);
    return 1;
}

int lua_share::read(lua_State* L)
{
    std::string name;
    std::string data;
    std::string result;
    int nTop = lua_gettop(L);

    if (nTop >= 1 && lua_isstring(L, 1))
    {
        name = lua_tostring(L, 1);
    }

    auto it = g_share.find(name);
    if (g_share.end() != it)
    {
        DWORD dwSize = it->second->GetCapacity();
        DWORD dwRead = 0;
        result.resize(dwSize);
        it->second->Read(&result[0], dwSize, &dwRead);
        result.resize(dwRead);
        lua_pushstring(L, result.c_str());
    }
    else
    {
        lua_pushstring(L, result.c_str());
    }

    return 1;
}

int lua_share::write(lua_State* L)
{
    std::string name;
    std::string data;
    int nTop = lua_gettop(L);

    if (nTop >= 1 && lua_isstring(L, 1))
    {
        name = lua_tostring(L, 1);
    }

    if (nTop >= 2 && lua_isstring(L, 2))
    {
        data = lua_tostring(L, 2);
    }

    auto it = g_share.find(name);
    if (g_share.end() == it)
    {
        lua_pushboolean(L, false);
    }
    else
    {
        it->second->Write(data.data(), (DWORD)data.size());
        lua_pushboolean(L, true);
    }

    return 1;
}